<template>
    <div class="contain">
        <div class="board">
            <div
                v-for="(bigSquare, bigIndex) in chessboard"
                :key="bigIndex + 'big'"
                class="big-square"
                :class="[lastSmallSquare === bigIndex || lastSmallSquare == -1? 'effective-area' : 'invalid-area']"
            >
                <div
                    v-for="(smallSquare, smallIndex) in bigSquare"
                    :key="smallIndex + 'small'"
                    class="small-square"
                    :class="{'last-chess': bigIndex === lastBigSquare && smallIndex === lastSmallSquare}"
                    @click="putChess(smallSquare)"
                >
                    <span
                        v-if="smallSquare.playerId"
                    >
                        {{playersScore.get(smallSquare.playerId)?.icon}}
                    </span>
                    <span v-else class="fade">
                        {{`${smallSquare.bigSquareName}${smallSquare.smallSquareIndex+1}`}}
                    </span>
                </div>
            </div>
        </div>

        <div class="game-info">
            <div>
                <div>本轮选手：{{playersScore.get(currentPlayId)?.name}} {{playersScore.get(currentPlayId)?.icon}}</div>
                <div
                    v-for="(playerId, sIndex) in [...playersScore.keys()]"
                    :key="sIndex + 'score'"
                >
                    <span>
                        {{playersScore.get(playerId)?.name}} 的当前积分：
                    </span>
                    <span>
                        {{playersScore.get(playerId)?.score}}
                    </span>
                </div>
                <div
                    v-if="isFinished"
                    class="finished"
                >
                    <span>本局游戏结束，{{result}}</span>
                </div>
                <button @click="resetGame">重新开始</button>
            </div>

            <div class="note">
                <div> 本程序由 up 主 <a href="https://space.bilibili.com/500146471" target="_blank">@爱思考的乌鸦</a> 提供思路 </div>
                <div> 由 up 主 <a href="https://space.bilibili.com/8212729" target="_blank">@冬灰条</a> 初步编写程序 </div>
                <div> 直播弹幕对战版也会同步到<a href="https://space.bilibili.com/8212729" target="_blank"> @冬灰条</a> 的直播间 </div>
                <div> 欢迎在 b 站以私聊 & 评论等形式向我们反馈程序的优化建议 </div>
            </div>
        </div>
    </div>
</template>

<script lang='ts'>
import { reactive, ref } from 'vue';
export default {
    setup() {
        // 初始化整个棋盘的数据
        // 把棋盘数据变成响应式
        interface SmallSquare {
            bigSquareIndex: number;
            bigSquareName: string;
            smallSquareIndex: number;
            playerId: string;
        };
        const chessboard = reactive([] as SmallSquare[][]);
        const chessboardInit = () => {
            // 清空棋盘
            chessboard.length = 0;
            const bigSquareName = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
            // 通过两个循环赋值
            for(let bigSquareIndex = 0; bigSquareIndex < 9; bigSquareIndex ++) {
                const bigSquare = [];
                for(let smallSquareIndex = 0; smallSquareIndex < 9; smallSquareIndex ++) {
                    bigSquare.push({
                        bigSquareName: bigSquareName[bigSquareIndex],
                        bigSquareIndex: bigSquareIndex,
                        smallSquareIndex,
                        playerId: ''
                    });
                }
                chessboard.push(bigSquare);
            }
        }
        chessboardInit();

        // 初始化玩家信息
        interface Player {
            icon: string;
            name: string;
            score: number;
        }
        const playersScore: Map<string, Player> = new Map();
        playersScore.set('1', {
            icon: '⭐',
            name: '玩家 1',
            score: 0
        })
        playersScore.set('2' , {
            icon: '🌕',
            name: '玩家 2',
            score: 0
        })

        // 玩家下棋子
        // 用来记录可选区域（上一颗棋子对应的小九宫格的位置）
        const lastSmallSquare = ref(-1);
        // 用来记录上一颗棋子所在的九宫格
        const lastBigSquare = ref(-1)
        // 用来记录当前玩家
        const currentPlayId = ref('1');
        const putChess = (chess: SmallSquare) => {
            // 如果当前已经有人下在这个格子上，就拦截
            if(chess.playerId) return;
            // 如果是刚开始游戏，或者当前的棋子不在有效区，就拦截
            if(lastSmallSquare.value != -1 && chess.bigSquareIndex != lastSmallSquare.value) return;
            // 记录有效区的索引
            lastSmallSquare.value = chess.smallSquareIndex;
            // 记录上一颗棋子所在的九宫格
            lastBigSquare.value = chess.bigSquareIndex;
            // 把选手的id填入表格
            chessboard[chess.bigSquareIndex][chess.smallSquareIndex].playerId = currentPlayId.value;
            // 切换选手
            const playerIdArr: string[] = [...playersScore.keys()];
            currentPlayId.value = currentPlayId.value === playerIdArr[0] ? playerIdArr[1] : playerIdArr[0];
            // 统计分数
            caculateScore();
            // 如果棋盘满了，结束游戏
            if(checkIsFinish()) {
                // 得出比分结果
                getResult();
                isFinished.value = true;
            }
        }

        // 可以得分的索引组合
        const winArr = [
            [0, 1, 2],
            [3, 4, 5],
            [6, 7, 8],
            [0, 3, 6],
            [1, 4, 7],
            [2, 5, 8],
            [0, 4, 8],
            [2, 4, 6]
        ]
        // 统计一个九宫格中的得分情况
        const bigSquareScore = (bigSquar: SmallSquare[]) => {
            // 遍历胜利数组
            winArr.forEach(array => {
                const [one, two, three] = array;
                // 如果这几个格子都有棋子，并且都是同一个玩家
                if (
                    bigSquar[one].playerId &&
                    bigSquar[two].playerId &&
                    bigSquar[three].playerId &&
                    bigSquar[one].playerId === bigSquar[two].playerId &&
                    bigSquar[one].playerId === bigSquar[three].playerId
                ) {
                    // 该玩家的分数加 1
                    playersScore.get(bigSquar[one].playerId)!.score ++;
                }
            })
        }
        // 重置玩家积分（清空）
        const resetPlayerScore = () => {
            playersScore.forEach(player => {
                player.score = 0;
            })
        }

        const isFinished = ref(false);
        // 不跨格计分模式下，统计所有九宫格的得分情况
        const caculateScore = () => {
            // 先清空
            resetPlayerScore();
            // 再遍历统计
            chessboard.forEach(bigSquar => {
                bigSquareScore(bigSquar);
            });
        }
        const a = [
            0, 1, 2,
            3, 4, 5,
            6, 7, 8
        ];
        // 跨格计分模式下，统计所有九宫格得分情况
        const crossRule: any = {
            0: {
                use: [
                    {add: 0, index: [0, 1, 2, 3, 4, 5, 6, 7, 8]}
                ],
                disabled:[]
            },
            1: {
                use: [
                    {add: 0, index: [1, 2, 4, 5, 7, 8]},
                    {add: 1, index: [0, 3, 6]}
                ],
                disabled:[2, 5, 8]
            },
            2: {
                use: [
                    {add: 0, index: [2, 5, 8]},
                    {add: 1, index: [0, 1, 3, 4, 6, 7]}
                ],
                disabled:[2, 5, 8]
            },
            3: {
                use: [
                    {add: 0, index: [3, 4, 5, 6, 7, 8]},
                    {add: 3, index: [0, 1, 2]}
                ],
                disabled:[6, 7, 8]
            },
            4: {
                use: [
                    {add: 0, index: [4, 5, 7, 8]},
                    {add: 1, index: [3, 4]},
                    {add: 3, index: [1, 2]},
                    {add: 4, index: [0]},
                ],
                disabled:[2, 5, 6, 7, 8]
            },
            5: {
                use: [
                    {add: 0, index: [5, 8]},
                    {add: 1, index: [3, 4, 6, 7]},
                    {add: 3, index: [2]},
                    {add: 4, index: [0, 1]},
                ],
                disabled:[2, 5, 6, 7, 8]
            },
            6: {
                use: [
                    {add: 0, index: [6, 7, 8]},
                    {add: 3, index: [0, 1, 2, 3, 4, 5]},
                ],
                disabled:[6, 7, 8]
            },
            7: {
                use: [
                    {add: 0, index: [7, 8]},
                    {add: 1, index: [6]},
                    {add: 3, index: [1, 2, 4, 5]},
                    {add: 4, index: [0, 3]},
                ],
                disabled:[2, 5, 6, 7, 8]
            },
            8: {
                use: [
                    {add: 0, index: [8]},
                    {add: 1, index: [6, 7]},
                    {add: 3, index: [2, 5]},
                    {add: 4, index: [0, 1, 3, 4]},
                ],
                disabled:[2, 5, 6, 7, 8]
            },
        }
        interface CrossBlock {
            add: number;
            index: number[];
        }
        const crossCaculateScore = () => {
            // 遍历每个大九宫格
            for (let bigSquareIndex = 0; bigSquareIndex < 9; bigSquareIndex ++) {
                // 遍历每个九宫格的每一个格子
                for (let smallSquareIndex = 0; smallSquareIndex < 9; smallSquareIndex ++) {
                    // 如果该格子不能跨格凑成九宫格，则跳过循环
                    if (crossRule[smallSquareIndex].disabled.includes(bigSquareIndex)) continue;
                    const bigSquar: SmallSquare[] = [];
                    crossRule[smallSquareIndex].use.forEach((element: CrossBlock) => {
                        element.index.forEach(block => {
                            bigSquar.push(chessboard[bigSquareIndex + element.add][block])
                        });
                    });
                }
            }
        }
        // 查看是否结束游戏，如果有空元素，就返回 false
        const checkIsFinish = () => {
            // 查看有效区是否满了
            const bigSquar = chessboard[lastSmallSquare.value];
            return !bigSquar.some(chess => !chess.playerId);
        }

        // 对比出谁是胜者
        const result = ref('')
        const getResult = () => {
            const player = [...playersScore.values()];
            if(player[0].score === player[1].score) {
                return result.value = '平局';
            }
            result.value = player[0].score > player[1].score ?
                           `${player[0].name} 胜出` :
                           `${player[1].name} 胜出`
        }

        const resetGame = () => {
            chessboardInit();
            resetPlayerScore();
            lastSmallSquare.value = -1;
            isFinished.value = false;
            currentPlayId.value = [... playersScore.keys()][0];
        }

        return {
            chessboard,
            lastSmallSquare,
            lastBigSquare,
            currentPlayId,
            playersScore,
            isFinished,
            result,
            resetGame,
            putChess
        }
    },
};
</script>

<style>
.effective-area {
    background-color: rgb(228, 255, 202);
}
.invalid-area:active {
    background-color: coral;
}
.fade {
    color: rgba(179, 179, 179, 0.335);
    font-size: 27px;
}
.board {
    width: 660px;
    min-width: 660px;
    display: flex;
    flex-wrap: wrap;
    border: 2px solid black;
}

.big-square {
    width: 216px;
    height: 216px;
    border: 2px solid black;
    display: flex;
    flex-wrap: wrap;
}

.last-chess {
    background-color:rgba(255, 0, 0, 0.403);

}
.small-square {
    width: 69px;
    height: 69px;
    border: 1px solid black;
    font-size: 30px;
    display:flex;
    justify-content: center;
    align-items: center;
}
.contain {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100vw;
    height: 100vh;
}
.game-info {
    font-size: 27px;
    margin-left: 30px;
    height: 651px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}
.finished {
    background-color: red;
    color: white;
    padding: 15px;
}
.note{
    font-size: 15px;
    color: gray;
}
</style>
